<!doctype html>
<html itemscope itemtype="http://schema.org/WebPage" lang="zh-cn" class="no-js">
  <head>
    <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="generator" content="Hugo 0.121.1">
<meta name="robots" content="index, follow">


<link rel="shortcut icon" href="/favicons/favicon.ico" >
<link rel="apple-touch-icon" href="/favicons/apple-touch-icon-180x180.png" sizes="180x180">
<link rel="icon" type="image/png" href="/favicons/favicon-16x16.png" sizes="16x16">
<link rel="icon" type="image/png" href="/favicons/favicon-32x32.png" sizes="32x32">
<link rel="icon" type="image/png" href="/favicons/android-36x36.png" sizes="36x36">
<link rel="icon" type="image/png" href="/favicons/android-48x48.png" sizes="48x48">
<link rel="icon" type="image/png" href="/favicons/android-72x72.png" sizes="72x72">
<link rel="icon" type="image/png" href="/favicons/android-96x96.png" sizes="96x96">
<link rel="icon" type="image/png" href="/favicons/android-144x144.png" sizes="144x144">
<link rel="icon" type="image/png" href="/favicons/android-192x192.png" sizes="192x192">

<title>ehcache 的多模块化最佳实践 | SOFAServerless</title>
<meta name="description" content="为什么需要最佳实践 CacheManager 初始化的时候存在共用 static 变量，多应用使用相同的 ehcache name，导致缓存互相覆盖。
最佳实践的几个要求 基座里必须引入 ehcache，模块里复用基座 在 springboot 里 ehcache 的初始化需要通过 Spring 里定义的 EhCacheCacheConfiguration 来创建，由于 EhCacheCacheConfiguration 是属于 Spring, Spring 统一放在基座里。 这里在初始化的时候，在做 Bean 初始化的条件判断时会走到类的检验， 如果 net.sf.ehcache.CacheManager 是。这里会走到 java native 方法上做判断，从当前类所在的 ClassLoader 里查找 net.sf.ehcache.CacheManager 类，所以基座里必须引入这个依赖，否则会报 ClassNotFound 的错误。 模块里将引入的 ehcache 排包掉（scope设置成 provide，或者使用自动瘦身能力） 模块使用自己 引入的 ehcache，照理可以避免共用基座 CacheManager 类里的 static 变量，而导致报错的问题。但是实际测试发现，模块安装的时候，在初始化 enCacheCacheManager 时， 这里在 new 对象时，需要先获得对象所属类的 CacheManager 是基座的 CacheManager。这里也不能讲 CacheManager 由模块 compile 引入，否则会出现一个类由多个不同 ClassLoader 引入导致的问题。 所以结论是，这里需要全部委托给基座加载。
最佳实践的方式 模块 ehcache 排包瘦身委托给基座加载 如果多个模块里有多个相同的 cacheName，需要修改 cacheName 为不同值。 如果不想改代码的方式修改 cache name，可以通过打包插件的方式动态替换 cacheName &amp;lt;plugin&amp;gt; &amp;lt;groupId&amp;gt;com.">
<meta property="og:title" content="ehcache 的多模块化最佳实践" />
<meta property="og:description" content="为什么需要最佳实践 CacheManager 初始化的时候存在共用 static 变量，多应用使用相同的 ehcache name，导致缓存互相覆盖。
最佳实践的几个要求 基座里必须引入 ehcache，模块里复用基座 在 springboot 里 ehcache 的初始化需要通过 Spring 里定义的 EhCacheCacheConfiguration 来创建，由于 EhCacheCacheConfiguration 是属于 Spring, Spring 统一放在基座里。 这里在初始化的时候，在做 Bean 初始化的条件判断时会走到类的检验， 如果 net.sf.ehcache.CacheManager 是。这里会走到 java native 方法上做判断，从当前类所在的 ClassLoader 里查找 net.sf.ehcache.CacheManager 类，所以基座里必须引入这个依赖，否则会报 ClassNotFound 的错误。 模块里将引入的 ehcache 排包掉（scope设置成 provide，或者使用自动瘦身能力） 模块使用自己 引入的 ehcache，照理可以避免共用基座 CacheManager 类里的 static 变量，而导致报错的问题。但是实际测试发现，模块安装的时候，在初始化 enCacheCacheManager 时， 这里在 new 对象时，需要先获得对象所属类的 CacheManager 是基座的 CacheManager。这里也不能讲 CacheManager 由模块 compile 引入，否则会出现一个类由多个不同 ClassLoader 引入导致的问题。 所以结论是，这里需要全部委托给基座加载。
最佳实践的方式 模块 ehcache 排包瘦身委托给基座加载 如果多个模块里有多个相同的 cacheName，需要修改 cacheName 为不同值。 如果不想改代码的方式修改 cache name，可以通过打包插件的方式动态替换 cacheName &lt;plugin&gt; &lt;groupId&gt;com." />
<meta property="og:type" content="article" />
<meta property="og:url" content="/docs/contribution-guidelines/runtime/ehcache/" /><meta property="article:section" content="docs" />
<meta property="article:published_time" content="2023-10-10T20:32:35+08:00" />
<meta property="article:modified_time" content="2023-11-19T20:12:43+08:00" />

<meta itemprop="name" content="ehcache 的多模块化最佳实践">
<meta itemprop="description" content="为什么需要最佳实践 CacheManager 初始化的时候存在共用 static 变量，多应用使用相同的 ehcache name，导致缓存互相覆盖。
最佳实践的几个要求 基座里必须引入 ehcache，模块里复用基座 在 springboot 里 ehcache 的初始化需要通过 Spring 里定义的 EhCacheCacheConfiguration 来创建，由于 EhCacheCacheConfiguration 是属于 Spring, Spring 统一放在基座里。 这里在初始化的时候，在做 Bean 初始化的条件判断时会走到类的检验， 如果 net.sf.ehcache.CacheManager 是。这里会走到 java native 方法上做判断，从当前类所在的 ClassLoader 里查找 net.sf.ehcache.CacheManager 类，所以基座里必须引入这个依赖，否则会报 ClassNotFound 的错误。 模块里将引入的 ehcache 排包掉（scope设置成 provide，或者使用自动瘦身能力） 模块使用自己 引入的 ehcache，照理可以避免共用基座 CacheManager 类里的 static 变量，而导致报错的问题。但是实际测试发现，模块安装的时候，在初始化 enCacheCacheManager 时， 这里在 new 对象时，需要先获得对象所属类的 CacheManager 是基座的 CacheManager。这里也不能讲 CacheManager 由模块 compile 引入，否则会出现一个类由多个不同 ClassLoader 引入导致的问题。 所以结论是，这里需要全部委托给基座加载。
最佳实践的方式 模块 ehcache 排包瘦身委托给基座加载 如果多个模块里有多个相同的 cacheName，需要修改 cacheName 为不同值。 如果不想改代码的方式修改 cache name，可以通过打包插件的方式动态替换 cacheName &lt;plugin&gt; &lt;groupId&gt;com."><meta itemprop="datePublished" content="2023-10-10T20:32:35+08:00" />
<meta itemprop="dateModified" content="2023-11-19T20:12:43+08:00" />
<meta itemprop="wordCount" content="159">
<meta itemprop="keywords" content="" /><meta name="twitter:card" content="summary"/><meta name="twitter:title" content="ehcache 的多模块化最佳实践"/>
<meta name="twitter:description" content="为什么需要最佳实践 CacheManager 初始化的时候存在共用 static 变量，多应用使用相同的 ehcache name，导致缓存互相覆盖。
最佳实践的几个要求 基座里必须引入 ehcache，模块里复用基座 在 springboot 里 ehcache 的初始化需要通过 Spring 里定义的 EhCacheCacheConfiguration 来创建，由于 EhCacheCacheConfiguration 是属于 Spring, Spring 统一放在基座里。 这里在初始化的时候，在做 Bean 初始化的条件判断时会走到类的检验， 如果 net.sf.ehcache.CacheManager 是。这里会走到 java native 方法上做判断，从当前类所在的 ClassLoader 里查找 net.sf.ehcache.CacheManager 类，所以基座里必须引入这个依赖，否则会报 ClassNotFound 的错误。 模块里将引入的 ehcache 排包掉（scope设置成 provide，或者使用自动瘦身能力） 模块使用自己 引入的 ehcache，照理可以避免共用基座 CacheManager 类里的 static 变量，而导致报错的问题。但是实际测试发现，模块安装的时候，在初始化 enCacheCacheManager 时， 这里在 new 对象时，需要先获得对象所属类的 CacheManager 是基座的 CacheManager。这里也不能讲 CacheManager 由模块 compile 引入，否则会出现一个类由多个不同 ClassLoader 引入导致的问题。 所以结论是，这里需要全部委托给基座加载。
最佳实践的方式 模块 ehcache 排包瘦身委托给基座加载 如果多个模块里有多个相同的 cacheName，需要修改 cacheName 为不同值。 如果不想改代码的方式修改 cache name，可以通过打包插件的方式动态替换 cacheName &lt;plugin&gt; &lt;groupId&gt;com."/>




<link rel="preload" href="/scss/main.min.526354c4efc1a4747972ed64c3be00f7db62aec5f0a3e6ae42052f97e2675d86.css" as="style">
<link href="/scss/main.min.526354c4efc1a4747972ed64c3be00f7db62aec5f0a3e6ae42052f97e2675d86.css" rel="stylesheet" integrity="">

<script
  src="https://code.jquery.com/jquery-3.6.3.min.js"
  integrity="sha512-STof4xm1wgkfm7heWqFJVn58Hm3EtS31XFaagaa8VMReCXAkQnJZ+jEy8PCC/iT18dFy95WcExNHFTqLyp72eQ=="
  crossorigin="anonymous"></script>
<link rel="stylesheet" href="/css/prism.css"/>
<link href="/img/logo.svg" rel="icon" type="image/svg">
<link href="/search/pagefind-ui.css" rel="stylesheet">
<script src="/search/pagefind-ui.js" type="text/javascript"></script>

<script>
    window.addEventListener('DOMContentLoaded', (event) => {
        new PagefindUI({ element: ".td-search" });
    });
</script>


<script>
var doNotTrack = false;
if (!doNotTrack) {
	window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
	ga('create', 'G-DZ8Q3F0GZ7', 'auto');
	
	ga('send', 'pageview');
}
</script>
<script async src='https://www.google-analytics.com/analytics.js'></script>

<script async src="https://www.googletagmanager.com/gtag/js?id=G-DZ8Q3F0GZ7"></script>
<script>
var doNotTrack = false;
if (!doNotTrack) {
	window.dataLayer = window.dataLayer || [];
	function gtag(){dataLayer.push(arguments);}
	gtag('js', new Date());
	gtag('config', 'G-DZ8Q3F0GZ7');
}
</script>
  </head>
  <body class="td-page">
    <header>
      <nav class="td-navbar navbar-dark js-navbar-scroll">
<div class="container-fluid flex-column flex-md-row">
  <a class="navbar-brand" href="/"><span class="navbar-brand__logo navbar-logo"><svg width="26" height="29" viewBox="0 0 26 29" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><linearGradient x1="52.6662558%" y1="95.7312514%" x2="35.7492678%" y2="11.0078657%" id="linearGradient-wxw43fh1xd-1"><stop stop-color="#9822e4" offset="0"/><stop stop-color="#e643fa" offset="86.0585504%"/><stop stop-color="#f876ff" offset="100%"/></linearGradient><path d="M15.9275871 1.54432572 15.936122 1.5594269 15.9445709 1.57457632 5.01248933 7.79418913 7.699 9.304l8.8412359-4.72420311.8668497-.49490764C17.4171462 4.0791454 17.4272394 4.07345885 17.4373647 4.06782987c1.474137-.81952243 3.3335154-.28885241 4.1530379 1.18528466L10.875 11.088l2.864 1.609 8.843271-5.6213813c1.1038914-.6292563 2.5021428-.23250173 3.1230817.88617614C25.8984381 8.30965565 25.9998668 8.70204694 25.9998668 9.10116416V19.9436637c0 1.3476373-1.002317 2.484932-2.3392704 2.6542897L22.9421516 22.6889619V10.4257286L20.457252 12.0257475 20.457758 23.6880152c0 1.2665471-1.0267393 2.2932864-2.2932864 2.2932864H17.59115L17.590252 13.8727475 15.106 15.473 15.1067564 27.0588825c0 1.0695936-.855616100000001 1.9366704-1.911072 1.9366704C12.8696714 28.9955529 12.5490782 28.9110348 12.2643947 28.7500365L1.63270516 23.3171586C.159863707 22.5645249-.423980046 20.7604209.328653641 19.2875794L.372104915 19.2057013 12.0490412 25.0797183 12.049 22.086 1.98952173 16.7675786C.51279311 15.9867912-.0513787599 14.1567129.729408593 12.6799843L.744416289 12.6519572.759717752 12.6240895 12.049 18.593 12.0490412 15.2566254 1.7391964 9.45898637C1.44132502 9.2850324 1.19527431 9.0328708 1.02697438 8.72907568c-.516688418-.93266477-.189466545-2.11320819.7308705-2.63681754C6.19445786 3.56812633 9.52191759 1.67502747 11.7402241.412961569L11.7628911.400065593c1.4660277-.834070345 3.3306257-.321767634 4.164696 1.144260127z" id="path-wxw43fh1xd-2"/><linearGradient x1="50.6099966%" y1="31.6743333%" x2="50.2419846%" y2="73.0702907%" id="linearGradient-wxw43fh1xd-4"><stop stop-color="#8200b5" offset="0"/><stop stop-color="#8200b5" stop-opacity="0" offset="100%"/></linearGradient><linearGradient x1="50.6028666%" y1="31.6743333%" x2="50.2391561%" y2="73.0702907%" id="linearGradient-wxw43fh1xd-5"><stop stop-color="#8200b5" offset="0"/><stop stop-color="#8200b5" stop-opacity="0" offset="100%"/></linearGradient><linearGradient x1="90.8235257%" y1="50%" x2="3.24041867%" y2="52.9415572%" id="linearGradient-wxw43fh1xd-6"><stop stop-color="#dd3ff7" stop-opacity="0" offset="0"/><stop stop-color="#ca23e4" offset="100%"/></linearGradient><linearGradient x1="74.3272776%" y1="35.8586031%" x2="19.6895996%" y2="19.3309621%" id="linearGradient-wxw43fh1xd-7"><stop stop-color="#b800d1" stop-opacity="0" offset="0"/><stop stop-color="#ae00c5" offset="100%"/></linearGradient><linearGradient x1="97.0070676%" y1="71.8003287%" x2="11.3661868%" y2="30.5044309%" id="linearGradient-wxw43fh1xd-8"><stop stop-color="#940ec7" offset="0"/><stop stop-color="#c435f0" stop-opacity="0" offset="100%"/></linearGradient></defs><g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><g id="首页" transform="translate(-24.000000, -18.000000)"><g id="编组-4" transform="translate(24.000133, 16.000000)"><g id="路径-6-copy-2" transform="translate(0.000000, 2.004447)"><mask id="mask-wxw43fh1xd-3" fill="#fff"><use xlink:href="#path-wxw43fh1xd-2"/></mask><use id="Mask" fill="url(#linearGradient-wxw43fh1xd-1)" fill-rule="nonzero" xlink:href="#path-wxw43fh1xd-2"/><path d="M12.0490412 15.2684078 13.03943 15.5167092C14.3279076 16.0478608 15.1686754 17.3038563 15.1686754 18.6975193V18.7421449v9.047164l-3.1196342-1.4070083V15.2684078z" id="Path-114-Copy-2" fill="url(#linearGradient-wxw43fh1xd-4)" opacity=".69047619" mask="url(#mask-wxw43fh1xd-3)"/><path d="M22.9421516 10.4227424 23.8594661 10.2542707C24.8889759 10.219744 25.7876765 10.946368 25.9694916 11.9602841L26.0763097 12.5559692 26.0617858 22.9064645l-3.1196342-1.4070082V10.4227424z" id="Path-114-Copy-2" fill="url(#linearGradient-wxw43fh1xd-5)" opacity=".69047619" mask="url(#mask-wxw43fh1xd-3)"/><polygon id="Path-41" fill="url(#linearGradient-wxw43fh1xd-6)" mask="url(#mask-wxw43fh1xd-3)" points="7.6326499 9.31647968 11.9297751 6.77228295 14.9765833 9.31647968 10.7681311 11.1500753"/><path d="M6.16852974 12.7326226C8.05429918 13.6181711 7.86496926 14.83948 8.18831704 15.006813 8.70089861 15.2720748 9.14143095 17.098905 9.86115602 17.1695013 10.6949216 17.2512836 11.6478081 10.8552079 10.3936906 10.4556578 9.48069361 10.1647855 7.32719679 9.49121213 3.93320016 8.43493769c-.63204609 1.86851711.11306377 3.30107871 2.23532958 4.29768491z" fill="url(#linearGradient-wxw43fh1xd-7)" mask="url(#mask-wxw43fh1xd-3)" transform="translate(7.357416, 12.802608) rotate(-347.000000) translate(-7.357416, -12.802608)"/><polygon id="Path-43" fill="url(#linearGradient-wxw43fh1xd-8)" mask="url(#mask-wxw43fh1xd-3)" points="12.0699788 18.5615749 6.27140769 15.1359473 5.30588708 19.0963147 12.0699788 22.1120507"/></g></g></g></g></svg></span><span class="navbar-brand__name">SOFAServerless</span></a>
  <div class="td-navbar-nav-scroll ms-md-auto" id="main_navbar">
    <ul class="navbar-nav">
      <li class="nav-item">
        <a class="nav-link" href="/home/"><span>首页</span></a>
      </li>
      <li class="nav-item">
        <a class="nav-link active" href="/docs/"><span>产品文档</span></a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="/blog/"><span>最新信息</span></a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="/community/"><span>参与社区</span></a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="/user-cases/"><span>用户案例</span></a>
      </li>
      <li class="nav-item dropdown d-none d-lg-block">
        <div class="dropdown">
  <a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">中文</a>
  <ul class="dropdown-menu">
    <li><a class="dropdown-item" href="/no/"></a></li>
    </ul>
</div></li>
      </ul>
  </div>
  <div class="d-none d-lg-block">
    <div class="td-search">
  <div class="td-search__icon"></div>
  <input type="search" class="td-search__input form-control td-search-input" placeholder="站内搜索…" aria-label="站内搜索…" autocomplete="off">
</div>

  </div>
</div>
</nav>
    </header>
    <div class="container-fluid td-outer">
      <div class="td-main">
        <div class="row flex-xl-nowrap">
          <aside class="col-12 col-md-3 col-xl-2 td-sidebar d-print-none">
            <div id="td-sidebar-menu" class="td-sidebar__inner">
  <form class="td-sidebar__search d-flex align-items-center">
    <div class="td-search">
  <div class="td-search__icon"></div>
  <input type="search" class="td-search__input form-control td-search-input" placeholder="站内搜索…" aria-label="站内搜索…" autocomplete="off">
</div>

    <button class="btn btn-link td-sidebar__toggle d-md-none p-0 ms-3 fas fa-bars" type="button" data-bs-toggle="collapse" data-bs-target="#td-section-nav" aria-controls="td-section-nav" aria-expanded="false" aria-label="Toggle section navigation">
    </button>
  </form>
  <nav class="collapse td-sidebar-nav" id="td-section-nav">
    <div class="td-sidebar-nav__section nav-item dropdown d-block d-lg-none">
      <div class="dropdown">
  <a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">中文</a>
  <ul class="dropdown-menu">
    <li><a class="dropdown-item" href="/no/"></a></li>
    </ul>
</div>
    </div>
    <ul class="td-sidebar-nav__section pe-md-3 ul-0">
      <li class="td-sidebar-nav__section-title td-sidebar-nav__section with-child active-path" id="m-docs-li">
  <a href="/docs/" class="align-left ps-0 td-sidebar-link td-sidebar-link__section tree-root" id="m-docs"><span class="">产品文档</span></a>
  <ul class="ul-1">
    <li class="td-sidebar-nav__section-title td-sidebar-nav__section with-child" id="m-docsintroduction-li">
  <a href="/docs/introduction/" class="align-left ps-0 td-sidebar-link td-sidebar-link__section" id="m-docsintroduction"><span class="">产品介绍</span></a>
  <ul class="ul-2 foldable">
    <li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docsintroductionintro-and-scenario-li">
  <a href="/docs/introduction/intro-and-scenario/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docsintroductionintro-and-scenario"><span class="">简介与适用场景</span></a>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docsintroductionindustry-background-li">
  <a href="/docs/introduction/industry-background/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docsintroductionindustry-background"><span class="">行业背景</span></a>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section with-child" id="m-docsintroductionarchitecture-li">
  <a href="/docs/introduction/architecture/" class="align-left ps-0 td-sidebar-link td-sidebar-link__section" id="m-docsintroductionarchitecture"><span class="">架构介绍</span></a>
  <ul class="ul-3 foldable">
    <li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docsintroductionarchitecturearch-principle-li">
  <a href="/docs/introduction/architecture/arch-principle/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docsintroductionarchitecturearch-principle"><span class="">架构原理</span></a>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docsintroductionarchitectureclass-delegation-principle-li">
  <a href="/docs/introduction/architecture/class-delegation-principle/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docsintroductionarchitectureclass-delegation-principle"><span class="">基座与模块间类委托加载原理介绍</span></a>
</li>
  </ul>
</li>
  </ul>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docsquick-start-li">
  <a href="/docs/quick-start/" class="align-left ps-0 td-sidebar-link td-sidebar-link__section" id="m-docsquick-start"><span class="">快速开始</span></a>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docsvideo-training-li">
  <a href="/docs/video-training/" class="align-left ps-0 td-sidebar-link td-sidebar-link__section" id="m-docsvideo-training"><span class="">视频教程</span></a>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section with-child" id="m-docstutorials-li">
  <a href="/docs/tutorials/" class="align-left ps-0 td-sidebar-link td-sidebar-link__section" id="m-docstutorials"><span class="">用户手册</span></a>
  <ul class="ul-2 foldable">
    <li class="td-sidebar-nav__section-title td-sidebar-nav__section with-child" id="m-docstutorialsbase-create-li">
  <a href="/docs/tutorials/base-create/" class="align-left ps-0 td-sidebar-link td-sidebar-link__section" id="m-docstutorialsbase-create"><span class="">基座接入</span></a>
  <ul class="ul-3 foldable">
    <li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docstutorialsbase-createspringboot-and-sofaboot-li">
  <a href="/docs/tutorials/base-create/springboot-and-sofaboot/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docstutorialsbase-createspringboot-and-sofaboot"><span class="">SpringBoot 或 SOFABoot 升级为基座</span></a>
</li>
  </ul>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section with-child" id="m-docstutorialsmodule-create-li">
  <a href="/docs/tutorials/module-create/" class="align-left ps-0 td-sidebar-link td-sidebar-link__section" id="m-docstutorialsmodule-create"><span class="">模块接入</span></a>
  <ul class="ul-3 foldable">
    <li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docstutorialsmodule-createspringboot-and-sofaboot-li">
  <a href="/docs/tutorials/module-create/springboot-and-sofaboot/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docstutorialsmodule-createspringboot-and-sofaboot"><span class="">SpringBoot 或 SOFABoot 一键升级为模块</span></a>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docstutorialsmodule-createinit_by_archtype-li">
  <a href="/docs/tutorials/module-create/init_by_archtype/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docstutorialsmodule-createinit_by_archtype"><span class="">使用 maven archtype 脚手架自动生成</span></a>
</li>
  </ul>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docstutorialstrial_step_by_step-li">
  <a href="/docs/tutorials/trial_step_by_step/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docstutorialstrial_step_by_step"><span class="">基座与模块并行开发验证</span></a>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section with-child" id="m-docstutorialsmodule-development-li">
  <a href="/docs/tutorials/module-development/" class="align-left ps-0 td-sidebar-link td-sidebar-link__section" id="m-docstutorialsmodule-development"><span class="">模块研发</span></a>
  <ul class="ul-3 foldable">
    <li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docstutorialsmodule-developmentcoding-specification-li">
  <a href="/docs/tutorials/module-development/coding-specification/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docstutorialsmodule-developmentcoding-specification"><span class="">编码规范</span></a>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docstutorialsmodule-developmentmodule-slimming-li">
  <a href="/docs/tutorials/module-development/module-slimming/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docstutorialsmodule-developmentmodule-slimming"><span class="">模块瘦身</span></a>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docstutorialsmodule-developmentmodule-and-base-communication-li">
  <a href="/docs/tutorials/module-development/module-and-base-communication/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docstutorialsmodule-developmentmodule-and-base-communication"><span class="">模块与模块、模块与基座通信</span></a>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docstutorialsmodule-developmentmodule-dev-arkctl-li">
  <a href="/docs/tutorials/module-development/module-dev-arkctl/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docstutorialsmodule-developmentmodule-dev-arkctl"><span class="">模块本地开发</span></a>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docstutorialsmodule-developmentmodule-debug-li">
  <a href="/docs/tutorials/module-development/module-debug/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docstutorialsmodule-developmentmodule-debug"><span class="">模块测试</span></a>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docstutorialsmodule-developmentreuse-base-interceptor-li">
  <a href="/docs/tutorials/module-development/reuse-base-interceptor/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docstutorialsmodule-developmentreuse-base-interceptor"><span class="">复用基座拦截器</span></a>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docstutorialsmodule-developmentreuse-base-datasource-li">
  <a href="/docs/tutorials/module-development/reuse-base-datasource/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docstutorialsmodule-developmentreuse-base-datasource"><span class="">复用基座数据源</span></a>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docstutorialsmodule-developmentstatic-merge-deployment-li">
  <a href="/docs/tutorials/module-development/static-merge-deployment/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docstutorialsmodule-developmentstatic-merge-deployment"><span class="">静态合并部署</span></a>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docstutorialsmodule-developmentruntime-compatibility-list-li">
  <a href="/docs/tutorials/module-development/runtime-compatibility-list/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docstutorialsmodule-developmentruntime-compatibility-list"><span class="">模块中官方支持的中间件客户端</span></a>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docstutorialsmodule-developmentsofa-ark-li">
  <a href="/docs/tutorials/module-development/sofa-ark/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docstutorialsmodule-developmentsofa-ark"><span class="">SOFAArk 关键用户文档</span></a>
</li>
  </ul>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section with-child" id="m-docstutorialsmodule-operation-li">
  <a href="/docs/tutorials/module-operation/" class="align-left ps-0 td-sidebar-link td-sidebar-link__section" id="m-docstutorialsmodule-operation"><span class="">模块运维</span></a>
  <ul class="ul-3 foldable">
    <li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docstutorialsmodule-operationmodule-online-and-offline-li">
  <a href="/docs/tutorials/module-operation/module-online-and-offline/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docstutorialsmodule-operationmodule-online-and-offline"><span class="">模块上线与下线</span></a>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docstutorialsmodule-operationmodule-deployment-and-rollback-li">
  <a href="/docs/tutorials/module-operation/module-deployment-and-rollback/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docstutorialsmodule-operationmodule-deployment-and-rollback"><span class="">模块发布</span></a>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docstutorialsmodule-operationincompatible-base-and-module-upgrade-li">
  <a href="/docs/tutorials/module-operation/incompatible-base-and-module-upgrade/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docstutorialsmodule-operationincompatible-base-and-module-upgrade"><span class="">基座和模块不兼容发布</span></a>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docstutorialsmodule-operationmodule-scale-and-replace-li">
  <a href="/docs/tutorials/module-operation/module-scale-and-replace/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docstutorialsmodule-operationmodule-scale-and-replace"><span class="">模块扩缩容与替换</span></a>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docstutorialsmodule-operationoperation-and-scheduling-strategy-li">
  <a href="/docs/tutorials/module-operation/operation-and-scheduling-strategy/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docstutorialsmodule-operationoperation-and-scheduling-strategy"><span class="">模块发布运维策略</span></a>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docstutorialsmodule-operationarklet-standalone-usage-li">
  <a href="/docs/tutorials/module-operation/arklet-standalone-usage/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docstutorialsmodule-operationarklet-standalone-usage"><span class="">独立使用 Arklet</span></a>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docstutorialsmodule-operationmodule-information-viewing-li">
  <a href="/docs/tutorials/module-operation/module-information-viewing/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docstutorialsmodule-operationmodule-information-viewing"><span class="">模块信息查看</span></a>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docstutorialsmodule-operationmodule-service-li">
  <a href="/docs/tutorials/module-operation/module-service/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docstutorialsmodule-operationmodule-service"><span class="">模块Service</span></a>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docstutorialsmodule-operationcrd-definition-li">
  <a href="/docs/tutorials/module-operation/crd-definition/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docstutorialsmodule-operationcrd-definition"><span class="">所有 K8S 资源定义及部署方式</span></a>
</li>
  </ul>
</li>
  </ul>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section with-child active-path" id="m-docscontribution-guidelines-li">
  <a href="/docs/contribution-guidelines/" class="align-left ps-0 td-sidebar-link td-sidebar-link__section" id="m-docscontribution-guidelines"><span class="">参与社区</span></a>
  <ul class="ul-2 foldable">
    <li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docscontribution-guidelinesour-vision-li">
  <a href="/docs/contribution-guidelines/our-vision/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docscontribution-guidelinesour-vision"><span class="">开放包容理念</span></a>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docscontribution-guidelinescommunication-channel-li">
  <a href="/docs/contribution-guidelines/communication-channel/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docscontribution-guidelinescommunication-channel"><span class="">交流渠道</span></a>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section with-child" id="m-docscontribution-guidelinescontribution-li">
  <a href="/docs/contribution-guidelines/contribution/" class="align-left ps-0 td-sidebar-link td-sidebar-link__section" id="m-docscontribution-guidelinescontribution"><span class="">贡献社区</span></a>
  <ul class="ul-3 foldable">
    <li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docscontribution-guidelinescontributionlocal-dev-test-li">
  <a href="/docs/contribution-guidelines/contribution/local-dev-test/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docscontribution-guidelinescontributionlocal-dev-test"><span class="">本地开发测试</span></a>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docscontribution-guidelinescontributionfirst-pr-li">
  <a href="/docs/contribution-guidelines/contribution/first-pr/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docscontribution-guidelinescontributionfirst-pr"><span class="">完成第一次 PR 提交</span></a>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docscontribution-guidelinescontributionimprove-doc-and-process-and-issue-li">
  <a href="/docs/contribution-guidelines/contribution/improve-doc-and-process-and-issue/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docscontribution-guidelinescontributionimprove-doc-and-process-and-issue"><span class="">文档、Issue、流程贡献</span></a>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docscontribution-guidelinescontributionsermon-li">
  <a href="/docs/contribution-guidelines/contribution/sermon/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docscontribution-guidelinescontributionsermon"><span class="">组织会议和运营布道</span></a>
</li>
  </ul>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docscontribution-guidelinesrole-and-promotion-li">
  <a href="/docs/contribution-guidelines/role-and-promotion/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docscontribution-guidelinesrole-and-promotion"><span class="">社区角色与晋升</span></a>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docscontribution-guidelinessofa-ark-li">
  <a href="/docs/contribution-guidelines/sofa-ark/" class="align-left ps-0 td-sidebar-link td-sidebar-link__section" id="m-docscontribution-guidelinessofa-ark"><span class="">SOFAArk 技术文档</span></a>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section with-child" id="m-docscontribution-guidelinesarklet-li">
  <a href="/docs/contribution-guidelines/arklet/" class="align-left ps-0 td-sidebar-link td-sidebar-link__section" id="m-docscontribution-guidelinesarklet"><span class="">Arklet 技术文档</span></a>
  <ul class="ul-3 foldable">
    <li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docscontribution-guidelinesarkletarchitecture-li">
  <a href="/docs/contribution-guidelines/arklet/architecture/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docscontribution-guidelinesarkletarchitecture"><span class="">Arklet 架构设计与接口设计</span></a>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docscontribution-guidelinesarklethow-to-release-li">
  <a href="/docs/contribution-guidelines/arklet/how-to-release/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docscontribution-guidelinesarklethow-to-release"><span class="">如何发布 Arklet 版本</span></a>
</li>
  </ul>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section with-child" id="m-docscontribution-guidelinesmodule-controller-li">
  <a href="/docs/contribution-guidelines/module-controller/" class="align-left ps-0 td-sidebar-link td-sidebar-link__section" id="m-docscontribution-guidelinesmodule-controller"><span class="">ModuleController 技术文档</span></a>
  <ul class="ul-3 foldable">
    <li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docscontribution-guidelinesmodule-controllerarchitecture-li">
  <a href="/docs/contribution-guidelines/module-controller/architecture/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docscontribution-guidelinesmodule-controllerarchitecture"><span class="">ModuleController 架构设计</span></a>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docscontribution-guidelinesmodule-controllercrd-definition-li">
  <a href="/docs/contribution-guidelines/module-controller/crd-definition/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docscontribution-guidelinesmodule-controllercrd-definition"><span class="">CRD 模型设计</span></a>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docscontribution-guidelinesmodule-controllercore-code-structure-li">
  <a href="/docs/contribution-guidelines/module-controller/core-code-structure/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docscontribution-guidelinesmodule-controllercore-code-structure"><span class="">核心代码结构</span></a>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docscontribution-guidelinesmodule-controllermodule-lifecycle-li">
  <a href="/docs/contribution-guidelines/module-controller/module-lifecycle/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docscontribution-guidelinesmodule-controllermodule-lifecycle"><span class="">模块生命周期</span></a>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docscontribution-guidelinesmodule-controllersequence-diagram-li">
  <a href="/docs/contribution-guidelines/module-controller/sequence-diagram/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docscontribution-guidelinesmodule-controllersequence-diagram"><span class="">核心流程时序图</span></a>
</li>
  </ul>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section with-child" id="m-docscontribution-guidelinesarkctl-li">
  <a href="/docs/contribution-guidelines/arkctl/" class="align-left ps-0 td-sidebar-link td-sidebar-link__section" id="m-docscontribution-guidelinesarkctl"><span class="">Arkctl 技术文档</span></a>
  <ul class="ul-3 foldable">
    <li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docscontribution-guidelinesarkctlarchitecture-li">
  <a href="/docs/contribution-guidelines/arkctl/architecture/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docscontribution-guidelinesarkctlarchitecture"><span class="">Arkctl 技术文档</span></a>
</li>
  </ul>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section with-child active-path" id="m-docscontribution-guidelinesruntime-li">
  <a href="/docs/contribution-guidelines/runtime/" class="align-left ps-0 td-sidebar-link td-sidebar-link__section" id="m-docscontribution-guidelinesruntime"><span class="">多模块运行时适配或最佳实践</span></a>
  <ul class="ul-3 foldable">
    <li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docscontribution-guidelinesruntimelogj42-li">
  <a href="/docs/contribution-guidelines/runtime/logj42/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docscontribution-guidelinesruntimelogj42"><span class="">log4j2 的多模块化适配</span></a>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child active-path" id="m-docscontribution-guidelinesruntimeehcache-li">
  <a href="/docs/contribution-guidelines/runtime/ehcache/" class="align-left ps-0 active td-sidebar-link td-sidebar-link__page" id="m-docscontribution-guidelinesruntimeehcache"><span class="td-sidebar-nav-active-item">ehcache 的多模块化最佳实践</span></a>
</li>
  </ul>
</li>
  </ul>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section with-child" id="m-docsfaq-li">
  <a href="/docs/faq/" class="align-left ps-0 td-sidebar-link td-sidebar-link__section" id="m-docsfaq"><span class="">常见 FAQ</span></a>
  <ul class="ul-2 foldable">
    <li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docsfaqfaq-li">
  <a href="/docs/faq/faq/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docsfaqfaq"><span class="">常见问题列表</span></a>
</li><li class="td-sidebar-nav__section-title td-sidebar-nav__section without-child" id="m-docsfaqimport-full-springboot-in-module-li">
  <a href="/docs/faq/import-full-springboot-in-module/" class="align-left ps-0 td-sidebar-link td-sidebar-link__page" id="m-docsfaqimport-full-springboot-in-module"><span class="">如果模块独立引入 SpringBoot 框架部分会怎样？</span></a>
</li>
  </ul>
</li>
  </ul>
</li>
    </ul>
  </nav>
</div>

          </aside>
          <aside class="d-none d-xl-block col-xl-2 td-sidebar-toc d-print-none">
            
<div class="td-page-meta ms-2 pb-1 pt-2 mb-0">
<a href="https://github.com/sofastack/sofa-serverless/tree/master/docs/content/zh-cn/docs/contribution-guidelines/runtime/ehcache.md" class="td-page-meta--view" target="_blank" rel="noopener"><i class="fa-solid fa-file-lines fa-fw"></i> 查看页面源码</a>
  <a href="https://github.com/sofastack/sofa-serverless/edit/master/docs/content/zh-cn/docs/contribution-guidelines/runtime/ehcache.md" class="td-page-meta--edit" target="_blank" rel="noopener"><i class="fa-solid fa-pen-to-square fa-fw"></i> 编辑此页</a>
  <a href="https://github.com/sofastack/sofa-serverless/new/master/docs/content/zh-cn/docs/contribution-guidelines/runtime/ehcache.md?filename=change-me.md&amp;value=---%0Atitle%3A&#43;%22Long&#43;Page&#43;Title%22%0AlinkTitle%3A&#43;%22Short&#43;Nav&#43;Title%22%0Aweight%3A&#43;100%0Adescription%3A&#43;%3E-%0A&#43;&#43;&#43;&#43;&#43;Page&#43;description&#43;for&#43;heading&#43;and&#43;indexes.%0A---%0A%0A%23%23&#43;Heading%0A%0AEdit&#43;this&#43;template&#43;to&#43;create&#43;your&#43;new&#43;page.%0A%0A%2A&#43;Give&#43;it&#43;a&#43;good&#43;name%2C&#43;ending&#43;in&#43;%60.md%60&#43;-&#43;e.g.&#43;%60getting-started.md%60%0A%2A&#43;Edit&#43;the&#43;%22front&#43;matter%22&#43;section&#43;at&#43;the&#43;top&#43;of&#43;the&#43;page&#43;%28weight&#43;controls&#43;how&#43;its&#43;ordered&#43;amongst&#43;other&#43;pages&#43;in&#43;the&#43;same&#43;directory%3B&#43;lowest&#43;number&#43;first%29.%0A%2A&#43;Add&#43;a&#43;good&#43;commit&#43;message&#43;at&#43;the&#43;bottom&#43;of&#43;the&#43;page&#43;%28%3C80&#43;characters%3B&#43;use&#43;the&#43;extended&#43;description&#43;field&#43;for&#43;more&#43;detail%29.%0A%2A&#43;Create&#43;a&#43;new&#43;branch&#43;so&#43;you&#43;can&#43;preview&#43;your&#43;new&#43;file&#43;and&#43;request&#43;a&#43;review&#43;via&#43;Pull&#43;Request.%0A" class="td-page-meta--child" target="_blank" rel="noopener"><i class="fa-solid fa-pen-to-square fa-fw"></i> 添加子页面</a>
  <a href="https://github.com/sofastack/sofa-serverless/issues/new?title=ehcache%20%e7%9a%84%e5%a4%9a%e6%a8%a1%e5%9d%97%e5%8c%96%e6%9c%80%e4%bd%b3%e5%ae%9e%e8%b7%b5" class="td-page-meta--issue" target="_blank" rel="noopener"><i class="fa-solid fa-list-check fa-fw"></i> 提交文档问题</a>
  <a id="print" href="/docs/contribution-guidelines/runtime/_print/"><i class="fa-solid fa-print fa-fw"></i> 整节打印</a>

</div>

            <div class="td-toc">
        <nav id="TableOfContents">
  <ul>
    <li><a href="#为什么需要最佳实践">为什么需要最佳实践</a></li>
    <li><a href="#最佳实践的几个要求">最佳实践的几个要求</a></li>
    <li><a href="#最佳实践的方式">最佳实践的方式</a></li>
    <li><a href="#最佳实践的样例">最佳实践的样例</a></li>
  </ul>
</nav>
      </div>
    
            

          </aside>
          <main class="col-12 col-md-9 col-xl-8 ps-md-5" role="main">
            
  

            
            
<div class="td-content">
	<h1>ehcache 的多模块化最佳实践</h1>
	
	<header class="article-meta">
		
</header>
	<h2 id="为什么需要最佳实践">为什么需要最佳实践</h2>
<p>CacheManager 初始化的时候存在共用 static 变量，多应用使用相同的 ehcache name，导致缓存互相覆盖。</p>
<h2 id="最佳实践的几个要求">最佳实践的几个要求</h2>
<ol>
<li>基座里必须引入 ehcache，模块里复用基座</li>
</ol>
<p>在 springboot 里 ehcache 的初始化需要通过 Spring 里定义的 EhCacheCacheConfiguration 来创建，由于 EhCacheCacheConfiguration 是属于 Spring, Spring 统一放在基座里。
<img src="https://intranetproxy.alipay.com/skylark/lark/0/2023/png/149473/1700202934067-7a0d74b7-b765-4c96-ab95-6189602235b8.png#clientId=u4cdbd480-e8bb-4&amp;from=paste&amp;height=679&amp;id=u3a86e2ae&amp;originHeight=1358&amp;originWidth=2284&amp;originalType=binary&amp;ratio=2&amp;rotation=0&amp;showTitle=false&amp;size=801737&amp;status=done&amp;style=none&amp;taskId=ub2119003-e3dd-4276-83a3-bc0a8598185&amp;title=&amp;width=1142" alt="image.png"></p>
<p>这里在初始化的时候，在做 Bean 初始化的条件判断时会走到类的检验，
<img src="https://intranetproxy.alipay.com/skylark/lark/0/2023/png/149473/1700203147758-c2f4f211-27b1-408a-8a59-04b54a0602f3.png#clientId=u4cdbd480-e8bb-4&amp;from=paste&amp;height=532&amp;id=ea4Xj&amp;originHeight=1064&amp;originWidth=1052&amp;originalType=binary&amp;ratio=2&amp;rotation=0&amp;showTitle=false&amp;size=607056&amp;status=done&amp;style=none&amp;taskId=u59dc4240-37cd-4a97-8b57-0e71250149b&amp;title=&amp;width=526" alt="image.png">
如果 net.sf.ehcache.CacheManager 是。这里会走到 java native 方法上做判断，从当前类所在的 ClassLoader 里查找 net.sf.ehcache.CacheManager 类，所以基座里必须引入这个依赖，否则会报 ClassNotFound 的错误。
<img src="https://intranetproxy.alipay.com/skylark/lark/0/2023/png/149473/1700203220867-62f2b7be-e853-488c-a6bc-a95c874793f1.png#clientId=u4cdbd480-e8bb-4&amp;from=paste&amp;height=97&amp;id=u3ca967f5&amp;originHeight=194&amp;originWidth=1798&amp;originalType=binary&amp;ratio=2&amp;rotation=0&amp;showTitle=false&amp;size=104469&amp;status=done&amp;style=none&amp;taskId=u4957f800-31ee-40b3-bb09-487b9ab16ba&amp;title=&amp;width=899" alt="image.png"></p>
<ol start="2">
<li>模块里将引入的 ehcache 排包掉（scope设置成 provide，或者使用自动瘦身能力）</li>
</ol>
<p>模块使用自己 引入的 ehcache，照理可以避免共用基座 CacheManager 类里的 static 变量，而导致报错的问题。但是实际测试发现，模块安装的时候，在初始化 enCacheCacheManager 时，
<img src="https://intranetproxy.alipay.com/skylark/lark/0/2023/png/149473/1700203897715-c9f97922-b466-4e73-8319-1a0f5ec3cc73.png#clientId=u4cdbd480-e8bb-4&amp;from=paste&amp;height=211&amp;id=uaa50406f&amp;originHeight=422&amp;originWidth=2048&amp;originalType=binary&amp;ratio=2&amp;rotation=0&amp;showTitle=false&amp;size=235120&amp;status=done&amp;style=none&amp;taskId=ub3d92b21-fec0-4462-92ad-91449dcea2d&amp;title=&amp;width=1024" alt="image.png">
<img src="https://intranetproxy.alipay.com/skylark/lark/0/2023/png/149473/1700203915265-f42253e4-1ff4-4088-a87e-8b6e063540ba.png#clientId=u4cdbd480-e8bb-4&amp;from=paste&amp;height=107&amp;id=uedd0a010&amp;originHeight=214&amp;originWidth=1258&amp;originalType=binary&amp;ratio=2&amp;rotation=0&amp;showTitle=false&amp;size=101140&amp;status=done&amp;style=none&amp;taskId=u044240e0-fe55-4f77-b63e-41ebf9eca47&amp;title=&amp;width=629" alt="image.png">
这里在 new 对象时，需要先获得对象所属类的 CacheManager 是基座的 CacheManager。这里也不能讲 CacheManager 由模块 compile 引入，否则会出现一个类由多个不同 ClassLoader 引入导致的问题。
<img src="https://intranetproxy.alipay.com/skylark/lark/0/2023/png/149473/1700212320690-8112f0f7-7ab7-48a7-8d9d-95aa3d49492a.png#clientId=u4cdbd480-e8bb-4&amp;from=paste&amp;height=145&amp;id=ud90248f9&amp;originHeight=290&amp;originWidth=2736&amp;originalType=binary&amp;ratio=2&amp;rotation=0&amp;showTitle=false&amp;size=294518&amp;status=done&amp;style=none&amp;taskId=ue9c723ea-0a3b-4854-b069-402238e5fcd&amp;title=&amp;width=1368" alt="image.png"></p>
<p>所以结论是，这里需要全部委托给基座加载。</p>
<h2 id="最佳实践的方式">最佳实践的方式</h2>
<ol>
<li>模块 ehcache 排包瘦身委托给基座加载</li>
<li>如果多个模块里有多个相同的 cacheName，需要修改 cacheName 为不同值。</li>
<li>如果不想改代码的方式修改 cache name，可以通过打包插件的方式动态替换 cacheName</li>
</ol>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span> <span style="color:#204a87;font-weight:bold">&lt;plugin&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#204a87;font-weight:bold">&lt;groupId&gt;</span>com.google.code.maven-replacer-plugin<span style="color:#204a87;font-weight:bold">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#204a87;font-weight:bold">&lt;artifactId&gt;</span>replacer<span style="color:#204a87;font-weight:bold">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#204a87;font-weight:bold">&lt;version&gt;</span>1.5.3<span style="color:#204a87;font-weight:bold">&lt;/version&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#204a87;font-weight:bold">&lt;executions&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#8f5902;font-style:italic">&lt;!-- 打包前进行替换 --&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#204a87;font-weight:bold">&lt;execution&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#204a87;font-weight:bold">&lt;phase&gt;</span>prepare-package<span style="color:#204a87;font-weight:bold">&lt;/phase&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#204a87;font-weight:bold">&lt;goals&gt;</span>
</span></span><span style="display:flex;"><span>                <span style="color:#204a87;font-weight:bold">&lt;goal&gt;</span>replace<span style="color:#204a87;font-weight:bold">&lt;/goal&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#204a87;font-weight:bold">&lt;/goals&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#204a87;font-weight:bold">&lt;/execution&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#204a87;font-weight:bold">&lt;/executions&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#204a87;font-weight:bold">&lt;configuration&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#8f5902;font-style:italic">&lt;!-- 自动识别到项目target文件夹 --&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#204a87;font-weight:bold">&lt;basedir&gt;</span>${build.directory}<span style="color:#204a87;font-weight:bold">&lt;/basedir&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#8f5902;font-style:italic">&lt;!-- 替换的文件所在目录规则 --&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#204a87;font-weight:bold">&lt;includes&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#204a87;font-weight:bold">&lt;include&gt;</span>classes/j2cache/*.properties<span style="color:#204a87;font-weight:bold">&lt;/include&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#204a87;font-weight:bold">&lt;/includes&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#204a87;font-weight:bold">&lt;replacements&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#204a87;font-weight:bold">&lt;replacement&gt;</span>
</span></span><span style="display:flex;"><span>                <span style="color:#204a87;font-weight:bold">&lt;token&gt;</span>ehcache.ehcache.name=f6-cache<span style="color:#204a87;font-weight:bold">&lt;/token&gt;</span>
</span></span><span style="display:flex;"><span>                <span style="color:#204a87;font-weight:bold">&lt;value&gt;</span>ehcache.ehcache.name=f6-${parent.artifactId}-cache<span style="color:#204a87;font-weight:bold">&lt;/value&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#204a87;font-weight:bold">&lt;/replacement&gt;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#204a87;font-weight:bold">&lt;/replacements&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#204a87;font-weight:bold">&lt;/configuration&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#204a87;font-weight:bold">&lt;/plugin&gt;</span>
</span></span></code></pre></div><ol start="4">
<li>需要把 FactoryBean 的 shared 设置成 false</li>
</ol>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#5c35cc;font-weight:bold">@Bean</span><span style="color:#f8f8f8;text-decoration:underline">
</span></span></span><span style="display:flex;"><span><span style="color:#f8f8f8;text-decoration:underline">    </span><span style="color:#204a87;font-weight:bold">public</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#000">EhCacheManagerFactoryBean</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#000">ehCacheManagerFactoryBean</span><span style="color:#000;font-weight:bold">()</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#000;font-weight:bold">{</span><span style="color:#f8f8f8;text-decoration:underline">
</span></span></span><span style="display:flex;"><span><span style="color:#f8f8f8;text-decoration:underline">        </span><span style="color:#000">EhCacheManagerFactoryBean</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#000">factoryBean</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#ce5c00;font-weight:bold">=</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#204a87;font-weight:bold">new</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#000">EhCacheManagerFactoryBean</span><span style="color:#000;font-weight:bold">();</span><span style="color:#f8f8f8;text-decoration:underline">
</span></span></span><span style="display:flex;"><span><span style="color:#f8f8f8;text-decoration:underline">
</span></span></span><span style="display:flex;"><span><span style="color:#f8f8f8;text-decoration:underline">        </span><span style="color:#8f5902;font-style:italic">// 需要把 factoryBean 的 share 属性设置成 false</span><span style="color:#f8f8f8;text-decoration:underline">
</span></span></span><span style="display:flex;"><span><span style="color:#f8f8f8;text-decoration:underline">        </span><span style="color:#000">factoryBean</span><span style="color:#000;font-weight:bold">.</span><span style="color:#c4a000">setShared</span><span style="color:#000;font-weight:bold">(</span><span style="color:#204a87;font-weight:bold">true</span><span style="color:#000;font-weight:bold">);</span><span style="color:#f8f8f8;text-decoration:underline">
</span></span></span><span style="display:flex;"><span><span style="color:#f8f8f8;text-decoration:underline"></span><span style="color:#8f5902;font-style:italic">//        factoryBean.setShared(false);</span><span style="color:#f8f8f8;text-decoration:underline">
</span></span></span><span style="display:flex;"><span><span style="color:#f8f8f8;text-decoration:underline">        </span><span style="color:#000">factoryBean</span><span style="color:#000;font-weight:bold">.</span><span style="color:#c4a000">setCacheManagerName</span><span style="color:#000;font-weight:bold">(</span><span style="color:#4e9a06">&#34;biz1EhcacheCacheManager&#34;</span><span style="color:#000;font-weight:bold">);</span><span style="color:#f8f8f8;text-decoration:underline">
</span></span></span><span style="display:flex;"><span><span style="color:#f8f8f8;text-decoration:underline">        </span><span style="color:#000">factoryBean</span><span style="color:#000;font-weight:bold">.</span><span style="color:#c4a000">setConfigLocation</span><span style="color:#000;font-weight:bold">(</span><span style="color:#204a87;font-weight:bold">new</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#000">ClassPathResource</span><span style="color:#000;font-weight:bold">(</span><span style="color:#4e9a06">&#34;ehcache.xml&#34;</span><span style="color:#000;font-weight:bold">));</span><span style="color:#f8f8f8;text-decoration:underline">
</span></span></span><span style="display:flex;"><span><span style="color:#f8f8f8;text-decoration:underline">        </span><span style="color:#204a87;font-weight:bold">return</span><span style="color:#f8f8f8;text-decoration:underline"> </span><span style="color:#000">factoryBean</span><span style="color:#000;font-weight:bold">;</span><span style="color:#f8f8f8;text-decoration:underline">
</span></span></span><span style="display:flex;"><span><span style="color:#f8f8f8;text-decoration:underline">    </span><span style="color:#000;font-weight:bold">}</span><span style="color:#f8f8f8;text-decoration:underline">
</span></span></span></code></pre></div><p>否则会进入这段逻辑，初始化 CacheManager 的static 变量 instance. 该变量如果有值，且如果模块里 shared 也是ture 的化，就会重新复用 CacheManager 的 instance，从而拿到基座的 CacheManager, 从而报错。
<img src="https://intranetproxy.alipay.com/skylark/lark/0/2023/png/149473/1700360794825-3f7f4a63-22bc-49ea-81d1-83bd94804087.png#clientId=u2481e0c2-f328-4&amp;from=paste&amp;height=399&amp;id=u7432be71&amp;originHeight=798&amp;originWidth=1596&amp;originalType=binary&amp;ratio=2&amp;rotation=0&amp;showTitle=false&amp;size=422965&amp;status=done&amp;style=none&amp;taskId=u1e450639-4846-4b6a-9862-bac787ae8e5&amp;title=&amp;width=798" alt="image.png">
<img src="https://intranetproxy.alipay.com/skylark/lark/0/2023/png/149473/1700359643422-7b252689-7e0c-41f3-995e-cbc40726136e.png#clientId=u2481e0c2-f328-4&amp;from=paste&amp;height=161&amp;id=u80efa85e&amp;originHeight=322&amp;originWidth=2426&amp;originalType=binary&amp;ratio=2&amp;rotation=0&amp;showTitle=false&amp;size=339519&amp;status=done&amp;style=none&amp;taskId=u15aeda8f-e089-4bf0-8bc7-e47eff9d2f0&amp;title=&amp;width=1213" alt="image.png"></p>
<h2 id="最佳实践的样例">最佳实践的样例</h2>
<p>样例工程请<a href="https://github.com/sofastack/sofa-serverless/tree/master/samples/springboot-samples/cache/ehcache">参考这里</a></p>

	<style>
  .feedback--answer {
    display: inline-block;
  }
  .feedback--answer-no {
    margin-left: 1em;
  }
  .feedback--response {
    display: none;
    margin-top: 1em;
  }
  .feedback--response__visible {
    display: block;
  }
</style>
<div class="d-print-none">
<h2 class="feedback--title">Feedback</h2>
<p class="feedback--question">Was this page helpful?</p>
<button class="btn btn-primary mb-4 feedback--answer feedback--answer-yes">Yes</button>
<button class="btn btn-primary mb-4 feedback--answer feedback--answer-no">No</button>
<p class="feedback--response feedback--response-yes">
  很高兴文档对您有帮助! 欢迎<a href="https://github.com/sofastack/sofa-serverless/issues/new?assignees=&labels=&projects=&template=feature_request.md">为社区提建议</a>。
</p>
<p class="feedback--response feedback--response-no">
  很抱歉文档对您没帮助。邀请您<a href="https://github.com/sofastack/sofa-serverless/issues/new?assignees=&labels=&projects=&template=feature_request.md">为文档提建议</a>或者<a href="https://github.com/sofastack/sofa-serverless/tree/master/user-docs/content/zh-cn">直接完善该文档</a>。
</p>
</div>
<script>
  const yesButton = document.querySelector('.feedback--answer-yes');
  const noButton = document.querySelector('.feedback--answer-no');
  const yesResponse = document.querySelector('.feedback--response-yes');
  const noResponse = document.querySelector('.feedback--response-no');
  const disableButtons = () => {
    yesButton.disabled = true;
    noButton.disabled = true;
  };
  const sendFeedback = (value) => {
    if (typeof ga !== 'function') return;
    const args = {
      command: 'send',
      hitType: 'event',
      category: 'Helpful',
      action: 'click',
      label: window.location.pathname,
      value: value
    };
    ga(args.command, args.hitType, args.category, args.action, args.label, args.value);
  };
  yesButton.addEventListener('click', () => {
    yesResponse.classList.add('feedback--response__visible');
    disableButtons();
    sendFeedback(1);
  });
  noButton.addEventListener('click', () => {
    noResponse.classList.add('feedback--response__visible');
    disableButtons();
    sendFeedback(0);
  });
</script>

		<br />
	<div class="text-muted mt-5 pt-3 border-top">
  最后修改 November 19, 2023: <a href="https://github.com/sofastack/sofa-serverless/commit/79628fc813251d16b9b191306d71af9bb68bd84d">add ehcache principle (79628fc8)</a>
</div>

</div>


          </main>
        </div>
      </div>
      <footer class="td-footer row d-print-none">
  <div class="container-fluid">
    <div class="row mx-md-2">
      <div class="col-6 col-sm-4 text-xs-center order-sm-2">
        
        
        
<ul class="td-footer__links-list">
  
  <li class="td-footer__links-item" data-bs-toggle="tooltip" title="通过社区交流群" aria-label="通过社区交流群">
    <a target="_blank" rel="noopener" href="/docs/contribution-guidelines/communication-channel/" aria-label="通过社区交流群">
      <i class="fab fa-twitter"></i>
    </a>
  </li>
  
</ul>

        
        
      </div>
      <div class="col-6 col-sm-4 text-end text-xs-center order-sm-3">
        
        
        
<ul class="td-footer__links-list">
  
  <li class="td-footer__links-item" data-bs-toggle="tooltip" title="看这里" aria-label="看这里">
    <a target="_blank" rel="noopener" href="/docs/contribution-guidelines/contribution/first-pr/" aria-label="看这里">
      <i class="fab fa-github"></i>
    </a>
  </li>
  
</ul>

        
        
      </div>
      <div class="td-footer__copyright-etc col-12 col-sm-4 text-center py-2 order-sm-2">
        <span>&copy; 2023 SOFAServerless 开源社区 保留所有权利</span>
        
        
      </div>
    </div>
  </div>
</footer>
    </div>
    
  <script src="/js/main.min.1eb4262674b2d02aa8d18559fef13b166dbdfa627fd0a495c66e11577c026aa3.js" integrity="sha256-HrQmJnSy0Cqo0YVZ/vE7Fm29&#43;mJ/0KSVxm4RV3wCaqM=" crossorigin="anonymous"></script>
<script src='/js/prism.js'></script>
<script src='/js/tabpane-persist.js'></script>

  </body>
</html>